package com.JingYan.Thread;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 记录创建线程的方法
 *
 * @author Dong_Jia_Qi on 2022/6/3
 */
@Slf4j
@Controller
public class ThreadNew {

    /**
     * 创建线程的三种方式的对比
     * 实现Runnable、Callable接口:
     *      优势:还可以继承其他类
     *          在这种方式下，多个线程可以共享同一个target对象，所以非常适合多个相同线程来处理同一份资源的情况，从而可以将CPU、代码和数据分开，形成清晰的模型，较好地体现了面向对象的思想
     *      劣势:编程稍微复杂，如果要访问当前线程，则必须使用Thread.currentThread()方法
     * 继承Thread类:
     *      优势:编写简单，如果需要访问当前线程，则无需使用Thread.currentThread()方法，直接使用this即可获得当前线程
     *      劣势:线程类已经继承了Thread类，所以不能再继承其他父类。
     * Runnable和Callable的区别:
     *      (1) Callable规定（重写）的方法是call()，Runnable规定（重写）的方法是run()。
     *      (2) Callable的任务执行后可返回值，而Runnable的任务是不能返回值的。
     *      (3) call方法可以抛出异常，run方法不可以。
     *      (4) 运行Callable任务可以拿到一个Future对象，表示异步计算的结果。它提供了检查计算是否完成的方法，以等待计算的完成，并检索计算的结果。通过Future对象可以了解任务执行情况，可取消任务的执行，还可获取执行结果
     */



    /**
     * 1. 继承 Thread 类重写 run 方法,这里为了省事写的是匿名内部类
     */
    public void threadNew1(){
        Thread thread = new Thread("继承类线程") {
            @Override
            public void run() {
                log.info("创建Thread匿名实现类,创建线程成功");
            }
        };
        thread.start();

    }

    /**
     * 2. 创建 Thread 类,传入一个 Runnable 接口实现类,这里用的是 lambda 语法简化
     */
    public void threadNew2(){
        Thread thread = new Thread(
                () -> {log.info("创建 Runnable 匿名实现类,创建线程成功"); },"实现接口线程"
        );
        thread.start();
    }

    /**
     * 3. 创建 FutureTask 类,传入一个 Callable 接口实现类, Callable 要实习的是 call 方法
     *      通过 start 方法启动线程 通过 get 方法获得返回值
     */
    public void threadNew3(){
        FutureTask<Integer> ft = new FutureTask<>(
                ()-> {
                    log.info("创建 Callable 匿名实现类,创建线程成功");
                    return 1;
                }
        );
        new Thread(ft, "有返回值的线程").start();
        try {
            //可以通过 FutureTask 的get 方法获得对应的返回值
            Integer integer = ft.get();
            log.info("Callable 子线程的返回值：" + integer);
        } catch (InterruptedException e) {
            log.error("获取线程返回值失败",e);
        } catch (ExecutionException e) {
            log.error("获取线程返回值失败",e);
        }
    }


}
